package http.raw;

import com.alibaba.fastjson.JSON;
import com.erp.service.util.JSONHelper;

import org.apache.http.client.HttpClient;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;

import http.HTTPException;
import http.HTTPMethod;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream;

public class HttpRequest {

	private final static String TAG = HttpRequest.class.getSimpleName();

	// 请求超时时长
	private static int CONNECT_TIMEOUT = 20 * 1000;
	// 读取超时时长
	private static int READ_TIMEOUT = 20 * 1000;

	/**
	 * 设置请求超时时长
	 * 
	 * @param value
	 *            时长
	 */
	public static void setConnectTimeout(int value) {
		CONNECT_TIMEOUT = value;
	}

	/**
	 * 设置读取超时时长
	 * 
	 * @param value
	 *            时长
	 */
	public static void setReadTimeout(int value) {
		READ_TIMEOUT = value;
	}

	/**
	 * （GET）发送HTTP请求，返回实体
	 * 
	 * @param url
	 *            请求地址
	 * @param params
	 *            请求参数
	 * @param headers
	 *            请求头
	 * @param entityType
	 *            实体类型
	 * @return
	 */
	public <T> T sendRequestForEntity(String url, Map<String, String> params,
			Map<String, String> headers, Class<T> entityType)
			throws HTTPException {
		String res = sendRequest(HTTPMethod.GET, url, params, null, headers);

		if (res != null && res.length() > 0) {
			return JSONHelper.<T> deserialize(entityType, res);
		} else {
			return null;
		}
	}

	/**
	 * （GET）发送HTTP请求，返回实体列表
	 * 
	 * @param url
	 *            请求地址
	 * @param params
	 *            请求参数
	 * @param headers
	 *            请求头
	 * @param entityType
	 *            实体类型
	 * @return
	 */
	public <T> List<T> sendRequestForEntityList(String url,
			Map<String, String> params, Map<String, String> headers,
			Class<T> entityType) throws HTTPException {
		String res = sendRequest(HTTPMethod.GET, url, params, null, headers);

		if (res != null && res.length() > 0) {
			return JSONHelper.deserializeArray(entityType, res);
		} else {
			return null;
		}
	}

	/**
	 * （POST）发送HTTP请求，返回实体
	 * 
	 * @param url
	 *            请求地址
	 * @param params
	 *            请求参数
	 * @param headers
	 *            请求头
	 * @param entityType
	 *            实体类型
	 * @return
	 */
	public <T> T sendPostRequestForEntity(String url,
			Map<String, String> params, Map<String, String> datas,
			Map<String, String> headers, Class<T> entityType)
			throws HTTPException {
		String dataStr = JSON.toJSONString(datas);
		String res = sendRequest(HTTPMethod.POST, url, params, dataStr, headers);

		if (res != null && res.length() > 0) {
			return JSONHelper.<T> deserialize(entityType, res);
		} else {
			return null;
		}
	}

	/**
	 * （POST）发送HTTP请求，返回实体
	 * 
	 * @param param
	 *            请求参数
	 * @param entityType
	 *            实体类型
	 * @return
	 */
	public <T> T sendPostRequestForEntity(HTTPRequestParam param,
			Class<T> entityType) throws HTTPException {
		String res = sendRequest(HTTPMethod.POST, param.getUrl(),
				param.getParams(), param.getBodyData(), param.getHeaders());

		if (res != null && res.length() > 0) {
			return JSONHelper.<T> deserialize(entityType, res);
		} else {
			return null;
		}
	}

	/**
	 * （POST）发送HTTP请求，返回实体列表
	 * 
	 * @param url
	 *            请求地址
	 * @param params
	 *            请求参数
	 * @param headers
	 *            请求头
	 * @param entityType
	 *            实体类型
	 * @return
	 */
	public <T> List<T> sendPostRequestForEntityList(String url,
			Map<String, String> params, Map<String, String> datas,
			Map<String, String> headers, Class<T> entityType)
			throws HTTPException {
		String dataStr = JSON.toJSONString(datas);
		String res = sendRequest(HTTPMethod.POST, url, params, dataStr, headers);

		if (res != null && res.length() > 0) {
			return JSONHelper.deserializeArray(entityType, res);
		} else {
			return null;
		}
	}

	/**
	 * 发送HTTP请求
	 * 
	 * @author wqz
	 * 
	 * @param httpMethod
	 *            请求方式
	 * @param url
	 *            请求地址
	 * @param params
	 *            请求参数
	 * @param headers
	 *            请求头
	 * @return
	 */
	public String sendRequest(HTTPMethod httpMethod, String url,
			Map<String, String> params, String datas,
			Map<String, String> headers) throws HTTPException {
		switch (httpMethod) {
		case GET:
			return doGetRequest(url, params, headers);
		case POST:
			return doPostRequest(url, params, datas, headers);
		}
		return "";
	}

	private  String encodeUrl(Map<String, String> params) {
		if (params == null) {
			return "";
		}

		boolean isFirst = true;
		StringBuilder sb = new StringBuilder();
		Set<String> keys = params.keySet();

		for (String key : keys) {
			String value = params.get(key);

			if (isFirst)
				isFirst = false;
			else
				sb.append("&");

			try {
				sb.append(URLEncoder.encode(key, "UTF-8"))
						.append("=")
						.append(URLEncoder.encode(value, "UTF-8"));
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
		}

		return sb.toString();
	}

	/**
	 * 发送HTTP请求(GET方式)
	 * 
	 * @author wqz
	 * 
	 * @param url
	 *            请求地址
	 * @param params
	 *            请求参数
	 * @return
	 */
	private String doGetRequest(String url, Map<String, String> params,
			Map<String, String> headers) throws HTTPException {
		HttpURLConnection conn = null;

		try {
			StringBuilder sb = new StringBuilder(url);
			String pStr = encodeUrl(params);
			if (pStr != null && pStr.length() > 0) {
				if (url.indexOf("?") == -1)
					sb.append("?").append(pStr);
				else
					sb.append("&").append(pStr);
			}
			URL urlObj = new URL(sb.toString());

			conn = (HttpURLConnection) urlObj.openConnection();
			conn.setRequestMethod("GET");
			conn.setConnectTimeout(CONNECT_TIMEOUT);
			conn.setReadTimeout(READ_TIMEOUT);
			conn.setRequestProperty("Charset", "UTF-8");

			// 请求头参数
			if (headers != null) {
				for (String key : headers.keySet()) {
					conn.setRequestProperty(key, headers.get(key));
				}
			}

			conn.connect();
			return handleResponse(conn).toString();
		} catch (ConnectTimeoutException e1) {
			throw new HTTPException(40001, "请求链接超时");
		} catch (SocketTimeoutException e2) {
			throw new HTTPException(40002, "数据读取超时");
		} catch (IOException e3) {
			throw new HTTPException(40003, "请求失败");
		} finally {
			// status != 200 的时候，也要关闭
			if (conn != null)
				conn.disconnect();
		}
	}

	/**
	 * 发送HTTP请求(POST方式)
	 * 
	 * @author wqz
	 * 
	 * @param url
	 *            请求地址
	 * @param params
	 *            请求参数
	 * @return
	 */
	private String doPostRequest(String url, Map<String, String> params,
			String datas, Map<String, String> headers) throws HTTPException {
		HttpURLConnection conn = null;

		try {
			StringBuilder sb = new StringBuilder(url);
			String pStr = encodeUrl(params);
			if (pStr != null && pStr.length() > 0) {
				sb.append(url.indexOf("?") == -1 ? "?" : "&").append(pStr);
			}

			URL urlObj = new URL(sb.toString());
			conn = (HttpURLConnection) urlObj.openConnection();
			conn.setDoInput(true);
			conn.setDoOutput(true);
			conn.setUseCaches(false);
			conn.setInstanceFollowRedirects(false);
			conn.setRequestMethod("POST");
			conn.setConnectTimeout(CONNECT_TIMEOUT);
			conn.setReadTimeout(READ_TIMEOUT);
			conn.setRequestProperty("Connection", "Keep-Alive");
			conn.setRequestProperty("Charset", "UTF-8");
			conn.setRequestProperty("Content-type", "application/json");

			// 请求头参数
			if (headers != null) {
				for (String key : headers.keySet()) {
					conn.setRequestProperty(key, headers.get(key));
				}
			}
			conn.connect();

			DataOutputStream out = new DataOutputStream(conn.getOutputStream());
			out.write(datas.getBytes());
			out.flush();
			out.close();

			return handleResponse(conn).toString();
		} catch (ConnectTimeoutException e1) {
			throw new HTTPException(40001, "请求链接超时");
		} catch (SocketTimeoutException e2) {
			throw new HTTPException(40002, "数据读取超时");
		} catch (IOException e3) {
			throw new HTTPException(40003, "请求失败");
		} finally {
			// status != 200的时候，也要关闭
			if (conn != null)
				conn.disconnect();
		}
	}

	/**
	 * 处理HTTP请求返回结果
	 * 
	 * @author wqz
	 * 
	 * @param conn
	 *            链接对象
	 * @return
	 */
	private String handleResponse(HttpURLConnection conn) throws HTTPException {
		int status = 0;

		try {
			status = conn.getResponseCode();
		} catch (IOException e) {
			conn.disconnect();
			throw new HTTPException(40003, "获取状态码失败");
		}

		if (status == HttpURLConnection.HTTP_OK) {
			return readResult(conn);
		} else if (status == HttpURLConnection.HTTP_NO_CONTENT) {
			return "";
		} else {
			throw new HTTPException(status, "网络请求失败");
		}
	}

	/**
	 * 读取HTTP请求返回的值
	 * 
	 * @author wqz
	 * 
	 * @param conn
	 *            链接对象
	 * @return
	 */
	private String readResult(HttpURLConnection conn) {
		InputStream is = null;
		BufferedReader buffer = null;

		try {
			is = conn.getInputStream();

			String encode = conn.getContentEncoding();
			if (encode != null && encode.equals("gzip")) {
				is = new GZIPInputStream(is);
			}
			buffer = new BufferedReader(new InputStreamReader(is));
			StringBuilder sb = new StringBuilder();
			String line;
			while ((line = buffer.readLine()) != null) {
				sb.append(line);
			}
			return sb.toString();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (is != null) {
				try {
					is.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

			if (buffer != null) {
				try {
					buffer.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

			if (conn != null) {
				conn.disconnect();
			}
		}

		return "";
	}

	/**
	 * 创建HttpClient对象
	 * 
	 * @return
	 */
	public HttpClient getHttpClient() {
		// 创建 HttpParams 以用来设置 HTTP 参数（这一部分不是必需的）
		HttpParams httpParams = new BasicHttpParams();
		// 设置连接超时和 Socket 超时，以及 Socket 缓存大小
		HttpConnectionParams.setConnectionTimeout(httpParams, CONNECT_TIMEOUT);
		HttpConnectionParams.setSoTimeout(httpParams, READ_TIMEOUT);
		HttpConnectionParams.setSocketBufferSize(httpParams, 8192);
		// 设置重定向，缺省为 true
		HttpClientParams.setRedirecting(httpParams, true);
		// 设置 user agent
		String userAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2) Gecko/20100115 Firefox/3.6";
		HttpProtocolParams.setUserAgent(httpParams, userAgent);
		// 创建一个 HttpClient 实例
		// 注意 HttpClient httpClient = new HttpClient(); 是Commons HttpClient
		// 中的用法，在 Android 1.5 中我们需要使用 Apache 的缺省实现 DefaultHttpClient
		HttpClient httpClient = new DefaultHttpClient(httpParams);
		return httpClient;
	}

    public static String getUrlWithParams(String url,Map<String, String> params){
        StringBuffer sbf = new StringBuffer();
        if(null != params){
            int i = 0;
            for(Map.Entry<String, String> entry : params.entrySet()){
                try {
                    sbf.append(i==0?"?":"&").append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue().toString(), "UTF-8"));
                    i++;
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
        return url+sbf.toString();
    }
}
